// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/win/scoped_bstr.h"

#include <stdint.h>

#include "base/logging.h"

namespace base {
namespace win {

    ScopedBstr::ScopedBstr(const char16* non_bstr)
        : bstr_(SysAllocString(non_bstr))
    {
    }

    ScopedBstr::~ScopedBstr()
    {
        static_assert(sizeof(ScopedBstr) == sizeof(BSTR), "ScopedBstrSize");
        SysFreeString(bstr_);
    }

    void ScopedBstr::Reset(BSTR bstr)
    {
        if (bstr != bstr_) {
            // if |bstr_| is NULL, SysFreeString does nothing.
            SysFreeString(bstr_);
            bstr_ = bstr;
        }
    }

    BSTR ScopedBstr::Release()
    {
        BSTR bstr = bstr_;
        bstr_ = NULL;
        return bstr;
    }

    void ScopedBstr::Swap(ScopedBstr& bstr2)
    {
        BSTR tmp = bstr_;
        bstr_ = bstr2.bstr_;
        bstr2.bstr_ = tmp;
    }

    BSTR* ScopedBstr::Receive()
    {
        DCHECK(!bstr_) << "BSTR leak.";
        return &bstr_;
    }

    BSTR ScopedBstr::Allocate(const char16* str)
    {
        Reset(SysAllocString(str));
        return bstr_;
    }

    BSTR ScopedBstr::AllocateBytes(size_t bytes)
    {
        Reset(SysAllocStringByteLen(NULL, static_cast<UINT>(bytes)));
        return bstr_;
    }

    void ScopedBstr::SetByteLen(size_t bytes)
    {
        DCHECK(bstr_ != NULL) << "attempting to modify a NULL bstr";
        uint32_t* data = reinterpret_cast<uint32_t*>(bstr_);
        data[-1] = static_cast<uint32_t>(bytes);
    }

    size_t ScopedBstr::Length() const
    {
        return SysStringLen(bstr_);
    }

    size_t ScopedBstr::ByteLength() const
    {
        return SysStringByteLen(bstr_);
    }

} // namespace win
} // namespace base
